home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 001a / mskrmsrc.zip / MSSSEN.ASM < prev    next >
Assembly Source File  |  1991-10-24  |  63KB  |  1,915 lines

  1.     NAME    msssen
  2. ; File MSSSEN.ASM
  3.     include mssdef.h
  4. ;       Copyright (C) 1982,1991, Trustees of Columbia University in the
  5. ;       City of New York.  Permission is granted to any individual or
  6. ;       institution to use, copy, or redistribute this software as long as
  7. ;       it is not sold for profit and this copyright notice is retained.
  8. ; Edit history:
  9. ; 6 Sept 1991 version 3.11
  10. ; Last edit 7 Feb 1991
  11. ; Sliding Windows
  12.  
  13.     public    spar, rpar, nout, send, flags, trans, dtrans, packlen
  14.     public    send10, mail, newfn, errpack, sstate, response, ackmsg
  15.     public    pktnum, numpkt, cntretry, sndpak, sparmax, remprn
  16.  
  17. spmin    equ    20        ; Minimum packet size
  18. spmax    equ    94        ; Maximum packet size
  19.  
  20. data     segment
  21.     extrn    fsta:word, auxfile:byte, encbuf:byte, decbuf:byte, maxtry:byte
  22.     extrn    errlev:byte, kstatus:word, diskio:byte, rpacket:byte
  23.     extrn    windflag:byte, rstate:byte, fmtdsp:byte, windlow:byte
  24.     extrn    charids:word, portval:word, chkparflg:byte
  25.  
  26. flags    flginfo    <>
  27. trans    trinfo    <>        ; negotiated trans information
  28. dtrans    trinfo    <>        ; default trans information
  29. crlf    db    cr,lf,'$'
  30. ender    db    bell,bell,'$'
  31. cemsg    db    'User intervention',0
  32. erms14  db    'No response from the host',0
  33. erms15    db    'File not found',0
  34. erms16    db    'Unknown packet type',0
  35. erms17    db    'Too many retries',0
  36. erms24    db    'Unable to send packet',0
  37. erms25    db    'Host does not support Kermit MAIL command',0
  38. erms26    db    'File rejected by host',0
  39. erms27    db    'Error. No buffers in send routine',0
  40. erms30    db    ': File size',0
  41. erms31    db    ': Date/time',0
  42. erms32    db    ': Mailing refused',0
  43. erms33    db    ': File Type',0
  44. erms34    db    ': Transfer Char-set',0
  45. erms36    db    ': Unknown reason',0
  46. infms1  db    cr,'             Sending: In progress',cr,lf,'$'
  47. infms2  db    cr,'             Mailing: In progress',cr,lf,'$'
  48. infms3  db    'Completed',cr,lf,'$'
  49. infms4  db    'Failed',cr,lf,'$'
  50. infms5    db    'Remote name is ',0
  51. filhlp  db      ' A filename (possibly wild)$'
  52. filmsg    db    ' Local Source File  or press ENTER for prompts$'
  53. remfnm    db    ' Remote Destination File: ',0    ; asciiz
  54. lclfnm    db    ' Local Source File: ',0    ; asciiz
  55. mailhlp    db    ' Filename  mail-address  or press ENTER for prompts$'
  56. mailto    db    ' To: ',0            ; asciiz
  57. mailtohlp db    ' mail address (eg, user@host or host::user)$'
  58. mailflg    db    0        ; 1 if Mail, 0 if Send command
  59. printhlp db    ' Filename and any extra host''s printer paramters$'
  60. printpmt db    ' Host printer parameters: ',0    ; asciiz 
  61. printas    db    ' host''s printer parameters, such as /COPIES=2/QUE=HPLJ$'
  62. asmsg    db    ' as ',0
  63. sstate    db    0        ; current automata state
  64. pktnum    db    0        ; packet number
  65. sndcnt    db    0        ; retry counter for sndpak, internal
  66. filopn    db    0        ; 1 if disk file is open for reading
  67. tempseq    db    0        ; target sequence number for responses
  68. retry    db    0        ; current retry threshold
  69.     even
  70. attlist    dw    sat5t,sat1t,sat2t,sat3t,sat4t,sat6t,sat7t,0 ;attrib procedures
  71. attptr    dw    0        ; pointer to items in attlist
  72. numpkt    dw    0        ; number of packets for file group
  73. temp    dw    0
  74. temp4    dw    0
  75. ninefive dw    95        ; constant word for long packets
  76. data    ends
  77.  
  78. code1    segment
  79.     extrn bufclr:far, pakptr:far, bufrel:far, makebuf:far, chkwind:far
  80.     extrn getbuf:far, rpack:far, spack:far
  81. code1    ends
  82.  
  83. code    segment
  84.     extrn serini:near, comnd:near, init:near
  85.     extrn gtnfil:near, gtchr:near
  86.     extrn getfil:near, rprpos:near, prtasz:near, cxerr:near
  87.     extrn ermsg:near, rtmsg:near, cxmsg:near, stpos:near, decout:near
  88.     extrn doenc:near, dodec:near, lnout:near, winpr:near
  89.     extrn prompt:near, intmsg:near, msgmsg:near
  90.     extrn strcpy:near, strlen:near, pktsize:near, isfile:near
  91.     extrn pcwait:near, ihostr:near, begtim:near, endtim:near
  92.  
  93.     assume    cs:code, ds:data, es:nothing
  94.  
  95. ; Data structures comments.
  96. ; Sent raw text material (typically rpar and filenames) is placed in encbuf,
  97. ; which may be encoded by doenc. doenc needs an output buffer provided as
  98. ; a pointer generated here via procedure buflist. encbuf is 512 bytes long.
  99. ; Sent packet material is placed in buffers pointed at by buflist. These
  100. ; buffers are subdivisions of one large buffer bufbuf (private to msscom).
  101. ; Proceedure makebuf does the subdivision and initialization of contents.
  102. ; Received material is directed to buffer rbuf which is part of structure
  103. ; rpacket; rbuf is 128 bytes long.
  104. ; Rpack and Spack expect a pointer in SI to the packet data field, done in a
  105. ; pktinfo format.
  106.  
  107. ;    SEND filespec
  108. ;    MAIL filspec user@node
  109. ;    REMOTE PRINT filespec parameters
  110.  
  111. SEND    PROC    NEAR
  112.     mov    mailflg,0        ; Send command, not Mail command
  113.     mov    temp,0
  114.     jmp    short send1        ; join common code
  115.  
  116. MAIL:    mov    mailflg,1        ; set flag for Mail command vs Send
  117.     mov    temp,1            ; temp copy of mailflag
  118.     jmp    short send1
  119.  
  120. REMPRN:    mov    mailflg,2        ; REMOTE PRINT entry point
  121.     mov    temp,2
  122.  
  123. send1:    mov    auxfile,0        ; clear send-as name (in case none)
  124.     mov    dx,offset diskio.string ; address of filename string
  125.     mov    bx,offset filmsg    ; help message
  126.     cmp    mailflg,0        ; Mail command?
  127.     je    send2            ; e = no
  128.     mov    mailflg,0        ; clear in case error exit
  129.     mov    bx,offset mailhlp    ; help message
  130.     cmp    temp,2            ; REMOTE PRINT?
  131.     jne    send2            ; ne = no
  132.     mov    bx,offset printhlp    ; help message
  133. send2:    mov    ah,cmword        ; get input file spec
  134.     call    comnd
  135.     jnc    send2a            ; nc = success
  136.     ret                ; failure
  137. send2a:    cmp    diskio.string,'#'    ; first char a replacement for '?'?
  138.     jne    send2b            ; ne = no
  139.     mov    diskio.string,'?'    ; yes. Change '#' for '?'
  140. send2b:    or    ax,ax            ; any text given?
  141.     jz    send3            ; z = no, prompt
  142.     cmp    temp,0            ; Mail or REMOTE PRINT command?
  143.     jne    send5            ; ne = yes, require address etc
  144.     mov    bx,offset auxfile         ; send file under different name?
  145.     mov    dx,offset filhlp    ; help
  146.     mov    ah,cmline        ; allow embedded white space
  147.     call    comnd
  148.     jnc    send2c            ; nc = success
  149.     ret                ; failure
  150. send2c:    cmp    auxfile,'#'        ; first char a replacement for '?'?
  151.     jne    send2d            ; ne = no
  152.     mov    auxfile,'?'        ; change '#' to '?'
  153. send2d:    jmp    send6            ; join common completion code
  154.  
  155. send3:    mov    dx,offset lclfnm    ; prompt for local filename
  156.     call    prompt
  157.     mov    dx,offset diskio.string ; reload destination of user's text
  158.     mov    bx,offset filhlp    ; help
  159.     mov    ah,cmword        ; get filename
  160.     call    comnd            ; try again for a local filename
  161.     jnc    send3a            ; nc = success
  162.     ret                ; failure
  163. send3a:    cmp    diskio.string,'#'    ; first char a replacement for '?'?
  164.     jne    send3b            ; ne = no
  165.     mov    diskio.string,'?'    ; yes. Change '#' for '?'
  166. send3b:    push    ax
  167.     mov    ah,cmeol        ; get the terminating CR
  168.     call    comnd
  169.     pop    ax
  170.     jnc    send3c            ; nc = success
  171.     ret                ; failure
  172. send3c:    or    ax,ax            ; user's byte count
  173.     jz    send3            ; z = nothing was typed, get some
  174.  
  175. send4:    mov    dx,offset remfnm    ; ask for remote name first
  176.     cmp    temp,0            ; Mail command?
  177.     je    send4a            ; e = no
  178.     mov    dx,offset mailto    ; ask for name@host
  179.     cmp    temp,2            ; REMOTE PRINT?
  180.     jne    send4a            ; ne = no
  181.     mov    dx,offset printpmt    ; ask for host print parameters
  182. send4a:    call    prompt
  183. send5:    mov    bx,offset auxfile         ; send file under different name?
  184.     mov    dx,offset filhlp    ; help
  185.     cmp    temp,0            ; Mail command?
  186.     je    send5a            ; e = no
  187.     mov    dx,offset mailtohlp    ; help
  188.     cmp    temp,2            ; REMOTE PRINT?
  189.     jne    send5a            ; ne = no
  190.     mov    dx,offset printas    ; help for printer parameters
  191. send5a:    mov    ah,cmline        ; allow embedded white space
  192.     call    comnd
  193.     jnc    send5b            ; nc = success
  194.     ret                ; failure
  195. send5b:    cmp    temp,2            ; REM Print cmd?
  196.     je    send6            ; e = yes, allow no parameters
  197.     or    ax,ax            ; text entered?
  198.     jz    send4            ; z = no, get some
  199.  
  200. send6:    mov    flags.xflg,0        ; reset flag for normal file send[mtd]
  201.     mov    sstate,0        ; dummy state, must be illegal
  202.     mov    ax,temp            ; get temp mailflag
  203.     mov    mailflg,al        ; store in secure area for later
  204.     mov    ah,trans.sdelay        ; seconds to delay before sending
  205.     shl    ah,1            ; times 4*256 to get millisec
  206.     shl    ah,1            ;  for pcwait
  207.     mov    al,1            ; set low byte to 1 for no delay case
  208.     call    pcwait            ; wait number of millisec in ax    
  209. SEND10:                ; SEND10 is an entry point for REMote cmds
  210.     mov    kstatus,kssuc        ; global status, success
  211.     mov    windflag,0        ; init windows in use display flag
  212.     call    makebuf            ; make some packet buffers
  213.     call    bufclr            ; clear port buffer of old NAKs
  214.     call    packlen            ; compute packet length
  215.     call    cxerr            ; clear Last Error line
  216.     call    cxmsg            ; clear Last Message line
  217.     mov    ax,offset diskio.string    ; filename to send, can be wild
  218.     call    isfile            ; does file exist?
  219.     jnc    send12            ; carry reset = yes, file found
  220.     cmp    sstate,'S'        ; was this from a remote GET?
  221.     jne    send11            ; ne = no, print error and continue
  222.     mov    dx,offset erms15    ; file not found
  223.     mov    trans.chklen,1        ; send init checksum is always 1 char
  224.     call    ermsg
  225.     mov    bx,dx
  226.     call    errpack            ; go complain
  227.     mov    sstate,'A'        ; abort
  228.     ret
  229.  
  230. send11:    mov    ah,prstr
  231.     mov    dx,offset crlf
  232.     int    dos
  233.     mov    dx,offset erms15    ; 'file not found'
  234.     call    prtasz
  235.     or    errlev,kssend        ; set DOS error level
  236.     or    fsta.xstatus,kssend    ; set status
  237.     mov    kstatus,kssend        ; global status
  238.     mov    mailflg,0        ; clear Mail flag
  239.     clc                ; pretend successful completion
  240.     ret
  241.  
  242. send12:    call    serini            ; initialize serial port
  243.     jnc    send13            ; nc = success
  244.     or    errlev,kssend        ; say send failed
  245.     or    fsta.xstatus,kssend    ; set status
  246.     mov    kstatus,kssend        ; global status
  247.     mov    dx,offset erms14    ; no response from host
  248.     call    ermsg            ; show message
  249.     stc                ; return failure
  250.     ret
  251.  
  252. send13:    xor    ax,ax
  253.     mov    pktnum,al        ; set the packet number to zero
  254.     mov    fsta.pretry,ax         ; set the number of retries to zero
  255.     mov    numpkt,ax        ; number pkts send in this file group
  256.     mov    flags.cxzflg,al
  257.     mov    sstate,'S'        ; set the state to send initiate
  258.     mov    chkparflg,1        ; check for unexpected parity
  259.     call    ihostr            ; initialize the host (clear NAKs)
  260.     call    init            ; clear line and initialize buffers
  261.     test    flags.remflg,dquiet+dserial ; quiet or serial display mode?
  262.     jnz    send15            ; nz = yes, surpress msgs
  263.     call    stpos            ; show status of file transfer
  264.     mov    dx,offset infms1    ; Sending in progress message
  265.     cmp    mailflg,0        ; Sending, vs Mailing?
  266.     je    send14            ; e = yes, sending
  267.     mov    dx,offset infms2    ; Mailing in progress message
  268. send14:    mov    ah,prstr
  269.     int    dos
  270. send15:    jmp    short dispatch        ; sstate has initial state ('S')
  271. SEND    ENDP
  272.  
  273. dispatch proc    near            ; Dispatch on state variable sstate
  274.     mov    ah,sstate
  275.     cmp    ah,'S'            ; send initiate state?
  276.     jne    dispat2            ; ne = no
  277.     call    sinit            ; negotiate
  278.     jmp    short dispatch
  279.  
  280. dispat2:cmp    ah,'F'            ; file header state?
  281.     jne    dispat3            ; ne = no
  282.     call    sfile            ; send file header
  283.     jmp    short dispatch
  284.  
  285. dispat3:cmp    ah,'a'            ; send attributes state?
  286.     jne    dispat4            ; ne = no
  287.     call    sattr            ; send attributes
  288.     jmp    short dispatch
  289.  
  290. dispat4:cmp    ah,'D'            ; data send state?
  291.     jne    dispat5            ; ne = no
  292.     call    sdata            ; send data
  293.     jmp    short dispatch
  294.  
  295. dispat5:cmp    ah,'Z'            ; EOF state?
  296.     jne    dispat6
  297.     call    seof            ; do EOF processing
  298.     jmp    short dispatch
  299.  
  300. dispat6:cmp    ah,'B'            ; end of file group state?
  301.     jne    dispat7
  302.     call    seot
  303.     jmp    short dispatch
  304.  
  305. dispat7:cmp    ah,'E'            ; user intervention ^C or ^E?
  306.     jne    dispat8            ; ne = no
  307.     call    bufclr
  308.     mov    bx,offset cemsg        ; user intervention message
  309.     call    errpack            ; send error message
  310.     call    intmsg            ; show interrupt msg for Control-C-E
  311.  
  312. dispat8:push    ax                ; 'A' abort or 'C' completion
  313.     pop    ax
  314.     mov    mailflg,0        ; clear Mail flag
  315.     call    bufclr            ; release all buffers
  316.     mov    windlow,0
  317.     mov    pktnum,0
  318.     call    stpos            ; show status of file transfer
  319.     mov    dx,offset infms3    ; Completed message
  320.     cmp    sstate,'C'        ; send complete state?
  321.     je    dispat9            ; e = yes, else failure
  322.     mov    dx,offset infms4    ; Failed message
  323.     or    errlev,kssend        ; say send failed
  324.     or    fsta.xstatus,kssend    ; set status
  325.     mov    kstatus,kssend        ; global status
  326.  
  327. dispat9:test    flags.remflg,dquiet+dserial ; quiet or serial display mode?
  328.     jnz    dispa9a            ; nz = yes, keep going
  329.     mov    ah,prstr        ; show completed/failed message
  330.     int    dos
  331. dispa9a:cmp    flags.cxzflg,0        ; completed normally?
  332.     je    dispa10            ; e = yes
  333.     or    errlev,kssend        ; say send failed
  334.     or    fsta.xstatus,kssend+ksuser ; set status, failed + intervention
  335.     mov    kstatus,kssend+ksuser    ; global status
  336. dispa10:mov    ax,1        ; tell statistics this was a send operation
  337.     call    endtim            ; stop statistics counter
  338.     test    flags.remflg,dquiet    ; quiet display mode?
  339.     jnz    dispa13            ; nz = yes, no talking
  340.     call    intmsg            ; show any interruption
  341.     cmp    flags.belflg,0        ; Bell desired?
  342.     je    dispa13            ; e = no
  343.     mov    ah,prstr
  344.     mov    dx,offset ender        ; ring bells
  345.     int    dos
  346. dispa13:call    rprpos            ; position cursor
  347.     xor    al,al
  348.     mov    flags.cxzflg,al        ; clear flag for next command
  349.     mov    auxfile,al        ; clear send-as filename buffer
  350.     mov    flags.xflg,al        ; clear to-screen flag
  351.     mov    diskio.string,al    ; clear active filename buffer
  352.     mov    fsta.xname,al        ; clear statistics external name
  353.     clc
  354.     ret                ; return to main command parser
  355. dispatch endp
  356.  
  357. ; Enter with filespec in diskio.string, external name/mail address in auxfile
  358.  
  359. ; Send Initiate packet
  360. SINIT    PROC    NEAR
  361.     call    begtim            ; get tod for start of transfer
  362.     mov    trans.windo,1        ; one window slot before negotiations
  363.     call    makebuf            ; remake buffers for new windowing
  364.     call    packlen            ; compute packet length
  365.     xor    ax,ax
  366.     mov    windlow,al        ; window lower border
  367.     mov    pktnum,al        ; sequence number to use
  368.     mov    windflag,al        ; windows in use display flag
  369.     mov    al,dtrans.xchset    ; reset Transmission char set
  370.     mov    trans.xchset,al        ;  to the current user default
  371.     mov    al,dtrans.xtype        ; ditto for File Type
  372.     mov    trans.xtype,al
  373.     call    getbuf            ; get a buffer address into si
  374.     call    sparmax            ; set up our maximum capabilities
  375.     call    rpar            ; put them into the packet
  376.     mov    trans.chklen,1        ; Send init checksum is always 1 char
  377.     mov    [si].pktype,'S'        ; send-initiate packet
  378.     call    sndpak            ; send the packet
  379.     jnc    sinit2            ; nc = successful send
  380.     ret                ; failure, change state
  381.  
  382. sinit2:    mov    al,pktnum        ; packet just sent
  383.     mov    ah,maxtry        ; normal retry threshold
  384.     add    ah,ah
  385.     add    ah,maxtry        ; triple the normal threshold
  386.     call    response        ; get response
  387.     jnc    sinit3            ; nc = success
  388.     ret
  389.  
  390. sinit3:    push    si            ; ACK in window
  391.     mov    si,offset rpacket    ; point to packet for spar
  392.     call    spar            ; parse the received data
  393.     pop    si
  394.     call    makebuf            ; remake buffers for new windowing
  395.     call    packlen            ; update max send packet size
  396.     mov    pktnum,1        ; next sequence number after 'S' pkts
  397.     mov    windlow,1        ; lowest acceptable sequence received
  398.     cmp    mailflg,0        ; non-zero to do Mail command
  399.     je    sinit4            ; e = send, not mail command
  400.     cmp    flags.attflg,0        ; file attributes disabled?
  401.     je    sinit5            ; e = yes, so no Mail
  402.     test    trans.capas,8        ; can they do file attributes?
  403.     jz    sinit5            ; z = no, so cannot do Mail
  404. sinit4:    call    getfil            ; open the file
  405.     jc    sinit4a            ; c = error
  406.     mov    filopn,1        ; disk file is open
  407.     mov    sstate,'F'        ; set the state to file send
  408.     ret
  409.  
  410. sinit4a:mov    dx,offset erms15    ; file not found
  411.     jmp    giveup            ;  something is wrong, quit w/msgs
  412.  
  413.                     ; say Mail not supported by host
  414. sinit5:    mov    dx,offset erms25    ; say no mail today
  415.     call    ermsg            ; tell both sides
  416.     mov    sstate,'B'        ; go to EOT state
  417.     ret
  418. SINIT    ENDP
  419.  
  420. ; Send file header
  421. ; Enter with pktnum set for the next transmission, no buffer
  422.  
  423. SFILE    PROC    NEAR
  424.     call    begtim            ; start statistics
  425.     cmp    filopn,1        ; is file open already?
  426.     je    sfile1            ; e = yes
  427.     call    bufrel            ; release buffer for SI
  428.     mov    dx,offset erms24    ; cannot send packet
  429.     jmp    giveup            ; something is wrong, quit
  430.  
  431. sfile1:    mov    flags.cxzflg,0        ; clear ^C, ^E, ^X, ^Z flag 
  432.     call    getbuf            ; get a packet buffer, address in si
  433.     jnc    sfile2            ; nc = got one
  434.     mov    dx,offset erms27    ; no buffers
  435.     jmp    giveup            ; tell both sides and fail
  436.  
  437. sfile2:    mov    dx,offset encbuf    ; destination = encode source buffer
  438.     call    strlen            ; get length (w/o terminator) into cx
  439.     call    doenc            ; do encoding; length is in cx
  440.     mov    [si].pktype,'F'        ; File header packet
  441.     cmp    flags.xflg,0        ; REMOTE command? (goes to screen)
  442.     je    sfile3            ; e = no
  443.     mov    [si].pktype,'X'        ; use X rather than F for REMOTE cmds
  444. sfile3:    call    sndpak            ; send the packet
  445.     jnc    sfile4            ; nc = success
  446.     ret
  447.  
  448. sfile4:    mov    al,pktnum        ; want response for packet just sent
  449.     mov    ah,maxtry        ; retry threshold
  450.     call    response        ; get response
  451.     jnc    sfile5            ; nc = success (got an ACK)
  452.     ret
  453.  
  454. sfile5:    call    ackmsg            ; show any message in ACK
  455.     inc    pktnum            ; next pkt to send/rcv, from ackpak
  456.     and    pktnum,3fh        ; modulo 64
  457.     mov    sstate,'a'        ; set file attributes as next state
  458.     ret                ; return to do next state
  459. SFILE    ENDP
  460.  
  461. ; Send file attributes. Attributes: file size in bytes and kilobytes,
  462. ; file time and date, machine identification.
  463. ; Writes output to buffer encbuf.
  464. SATTR    PROC    NEAR
  465.     cmp    flags.attflg,0        ; allowed to do file attributes?
  466.     je    satt0            ; e = no
  467.     mov    attptr,offset attlist    ; point at list of attributes procs
  468.     test    trans.capas,8        ; can we do file attributes?
  469.     jnz    satt1            ; nz = yes
  470. satt0:    mov    sstate,'D'        ; set the state to send-data
  471.     ret
  472.  
  473. satt1:    mov    bx,attptr        ; ptr to list of attributes procedures
  474.     cmp    word ptr [bx],0        ; at end of list?
  475.     je    satt0            ; e = yes, do next state
  476.     call    getbuf            ; get buffer for sending
  477.     jnc    satt2            ; nc = got one
  478.     mov    dx,offset erms27    ; no buffers
  479.     jmp    giveup            ; tell both sides and fail
  480.  
  481. satt2:    mov    di,offset encbuf    ; address of a temp data buffer
  482.     mov    byte ptr [di],0        ; start with null terminator
  483.     push    es            ; save es around this work
  484.     push    ds
  485.     pop    es            ; set es to data segment for es:di
  486.     push    si
  487.     mov    bx,attptr        ; ptr to list of attributes routines
  488.     mov    bx,[bx]            ; de-reference one level
  489.     call    bx            ; do it
  490.     pop    si
  491.     pop    es
  492.     mov    byte ptr [di],0        ; insert null terminator in temp buf
  493.     mov    dx,offset encbuf
  494.     call    strlen            ; get length of this attribute to CX
  495.     cmp    cx,trans.maxdat        ; longer than any packet?
  496.     jbe    satt3            ; be = no, proceed
  497.     call    bufrel            ; release this buffer
  498.     mov    dx,offset erms24    ; "Unable to send packet"
  499.     call    ermsg            ; position cursor, display asciiz msg
  500.     mov    flags.cxzflg,'X'    ; say skip this file
  501.     mov    sstate,'Z'        ; move to EOF state
  502.     ret
  503.  
  504. satt3:    mov    ax,[si].datlen        ; data length for packet, so far
  505.     add    ax,cx            ; plus, maybe, this contribution
  506.     cmp    ax,trans.maxdat        ; new info fits into packet?
  507.     jg    satt4            ; g = no, send what we have
  508.     push    si            ; preserve packet structure pointer
  509.     push    es
  510.     push    ds
  511.     pop    es
  512.     mov    di,[si].datadr        ; packet buffer beginning
  513.     add    di,[si].datlen        ; plus current contents
  514.     add    [si].datlen,cx        ; say adding this many bytes
  515.     mov    si,offset encbuf    ; temp buffer is source of new info
  516.     cld                ; packet buffer is destination
  517.     rep    movsb            ; copy new material to packet buffer
  518.     pop    es
  519.     pop    si
  520.     add    attptr,2        ; next attributes procedure address
  521.     mov    bx,attptr
  522.     cmp    word ptr [bx],0        ; at end of list?
  523.     jne    satt2            ; ne = no, do next attribute proc
  524.     cmp    [si].datlen,0        ; any data to send?
  525.     jne    satt4            ; ne = yes
  526.     call    bufrel            ; release the unused buffer
  527.     mov    sstate,'D'        ; set the state to send-data
  528.     ret
  529.  
  530. satt4:    call    sndatt            ; send attributes packet, get response
  531.     jc    satt5            ; c = failure
  532.     jmp    satt1            ; get new buffer, do more attributes
  533. satt5:    ret                ; failure, change state
  534.  
  535.                     ; Send Attributes packet, local worker
  536. sndatt:    mov    [si].pktype,'A'        ; Attributes packet
  537.     call    sndpak            ; send the packet
  538.     jnc    sndat1            ; nc = success
  539.     ret
  540. sndat1:    mov    al,pktnum        ; get response for packet just sent
  541.     mov    ah,maxtry        ; retry threshold
  542.     call    response        ; get response
  543.     jnc    sndat2            ; nc = success
  544.     ret
  545.  
  546. sndat2:    inc    pktnum            ; sent and ack'd, next seqnum to use
  547.     and    pktnum,3fh
  548.     cmp    rpacket.datlen,0    ; any data in the ACK?
  549.     je    sndat3            ; e = no
  550.     mov    bx,rpacket.datadr    ; received data field
  551.     cmp    byte ptr[bx],'N'    ; are they refusing this file?
  552.     je    sndat4            ; e = yes, 'N' = refusing the file
  553. sndat3:    clc                ; say success
  554.     ret
  555.                     ; display file refusal reason
  556. sndat4:    test    flags.remflg,dquiet    ; quiet display?
  557.     jnz    sndat7            ; nz = yes
  558.     mov    dx,offset erms26    ; say host rejected the file 
  559.     call    ermsg
  560.     mov    cx,rpacket.datlen    ; display all reasons
  561. sndat5:    dec    cx            ; next byte
  562.     inc    bx            ; point to next data field item
  563.     cmp    cx,0            ; anything there?
  564.     jle    sndat7            ; b = no
  565.     mov    ah,[bx]            ; get reason code
  566.     mov    dx,offset erms30
  567.     cmp    ah,'1'            ; Byte count?
  568.     je    sndat6            ; e = yes
  569.     cmp    ah,'!'            ; Kilobyte count?
  570.     je    sndat6
  571.     mov    dx,offset erms31
  572.     cmp    ah,'#'            ; Date and Time?
  573.     je    sndat6            ; e = yes
  574.     mov    dx,offset erms32
  575.     cmp    ah,'+'            ; Mail?
  576.     je    sndat6            ; e = yes
  577.     mov    dx,offset erms33
  578.     cmp    ah,'"'            ; File Type?
  579.     je    sndat6
  580.     mov    dx,offset erms34
  581.     cmp    ah,'*'            ; Transfer Char-set?
  582.     je    sndat6
  583.     mov    dx,offset erms36    ; unknown reason
  584. sndat6:    call    prtasz            ; display reason
  585.     jmp    short sndat5        ; do any other reasons
  586. sndat7:    mov    flags.cxzflg,'X'    ; simulate Control-X to discard
  587.     mov    sstate,'Z'        ; send EOF with Discard
  588.     stc
  589.     ret
  590.  
  591. ; Individual attribute routines. Each expects DI to point to a free storage
  592. ; byte in an output buffer and it updates DI to the next free byte. Expects
  593. ; ES to be pointing at the data segment. OK to clobber SI here.
  594.  
  595. sat1t:    test    flags.attflg,attlen    ; can we send length attribute?
  596.     jz    sat1tx            ; z = no
  597.     mov    si,di            ; remember starting location
  598.     mov    byte ptr [di],'1'    ; file length (Bytes) specifier
  599.     mov    dx,diskio.sizehi    ; high word of length
  600.     mov    ax,diskio.sizelo    ; low word of length
  601.     add    di,2
  602.     call    lnout            ; convert file length, write to [di++]
  603.     mov    cx,di            ; compute field length
  604.     sub    cx,si
  605.     sub    cx,2
  606.     add    cl,32            ; field length to ascii
  607.     mov    [si+1],cl        ; length. Done with File Size
  608. sat1tx:    ret
  609.                     ; Kilobyte attribute
  610. sat2t:    test    flags.attflg,attlen    ; can we send length attribute?
  611.     jz    sat2tx            ; z = no
  612.     mov    byte ptr[di],'!'    ; file length (Kilobytes) specifier
  613.     inc    di
  614.     mov    temp4,di        ; remember place for count field
  615.     inc    di            ; data field
  616.     mov    dx,diskio.sizehi    ; high word of length, from file open
  617.     mov    ax,diskio.sizelo    ; low word of length
  618.     add    ax,1023            ; add 1023 to round up
  619.     adc    dx,0
  620.     mov    al,ah            ; do divide by 1024 bytes
  621.     mov    ah,dl
  622.     mov    dl,dh            ; divide by 256 part
  623.     xor    dh,dh
  624.     ror    dl,1            ; low bit to carry flag
  625.     rcr    ax,1            ; divide by two, with carry in
  626.     clc
  627.     ror    dl,1            ; low bit to carry flag
  628.     rcr    ax,1            ; divide by two, with carry in
  629.     and     dl,3fh            ; keep low six bits
  630.     call    lnout            ; convert file length
  631.     mov    cx,di            ; compute field length
  632.     sub    cx,temp4        ; count field location
  633.     add    cl,32-1            ; field length to ascii
  634.     push    di
  635.     mov    di,temp4        ; point at count field
  636.     mov    [di],cl            ; store field length
  637.     pop    di            ; Done with Kilobyte attribute
  638. sat2tx:    ret
  639.  
  640. sat3t:    test    flags.attflg,attdate    ; can we send file date and time?
  641.     jnz    sat3t1            ; nz = yes
  642.     ret
  643. sat3t1:    cld                ; file Date and Time
  644.     mov    al,'#'            ; creation date/time specifier
  645.     stosb                ; and point at field length
  646.     mov    al,17+32        ; length of date/time field, to ascii
  647.     stosb
  648.     xor    ah,ah
  649.     mov    al,diskio.dta+25    ; yyyyyyym from DOS via file open
  650.     shr    al,1            ; get year
  651.     add    ax,1980            ; add bias
  652.     xor    dx,dx
  653.     call    lnout            ; put year (1990) in buffer
  654.     mov    ax,word ptr diskio.dta+24 ; yyyyyyyym mmmddddd  year+month+day
  655.     shr    ax,1            ; month to al
  656.     xor    ah,ah
  657.     mov    cl,4
  658.     shr    al,cl            ; month to low nibble
  659.     mov    byte ptr[di],'0'    ; leading digit
  660.     inc    di
  661.     cmp    al,9            ; more than one digit?
  662.     jbe    sat3t2            ; be = no
  663.     mov    byte ptr[di-1],'1'    ; new leading digit
  664.     sub    al,10            ; get remainder
  665. sat3t2:    add    al,'0'            ; to ascii
  666.     stosb                ; end of month
  667.     mov    al,diskio.dta+24    ; get day of month
  668.     and    al,1fh            ; select day bits
  669.     xor    ah,ah
  670.     mov    cl,10
  671.     div    cl            ; quot = al, rem = ah
  672.     add    ax,'00'            ; add ascii bias
  673.     stosw                ; leading digit and end of date
  674.     mov    al,' '            ; space separator
  675.     stosb
  676.     mov    al,diskio.dta+23    ; hours  hhhhhmmm
  677.     mov    cl,3
  678.     shr    al,cl            ; move to low nibble
  679.     xor    ah,ah
  680.     mov    cl,10
  681.     div    cl            ; quot = al, rem = ah
  682.     add    ax,'00'            ; add ascii bias
  683.     stosw                ; store hours
  684.     mov    al,':'            ; separator
  685.     stosb
  686.     mov    ax,word ptr diskio.dta+22 ; get minutes: hhhhhmmm mmmsssss
  687.     mov    cl,5
  688.     shr    ax,cl            ; minutes to low byte
  689.     and    al,3fh            ; six bits for minutes
  690.     xor    ah,ah
  691.     mov    cl,10
  692.     div    cl
  693.     add    ax,'00'            ; add ascii bias
  694.     stosw
  695.     mov    al,':'            ; separator
  696.     stosb
  697.     mov    al,byte ptr diskio.dta+22 ; get seconds (double secs really)
  698.     and    al,1fh
  699.     shl    al,1            ; DOS counts by two sec increments
  700.     xor    ah,ah
  701.     mov    cl,10
  702.     div    cl
  703.     add    ax,'00'            ; add ascii bias
  704.     stosw
  705.     ret
  706.  
  707. sat4t:    mov    ax,'".'            ; machine indicator(.), 2 data bytes
  708.     cld
  709.     stosw
  710.     mov    ax,'8U'            ; U8 = Portable O/S, MSDOS
  711.     stosw
  712.     ret
  713.  
  714.  
  715. sat5t:    cmp    mailflg,0        ; Mailing or REMOTE PRINTing?
  716.     jne    sat5t1            ; ne = yes
  717.     ret
  718. sat5t1:    mov    byte ptr [di],'+'    ; Disposition specification
  719.     inc    di
  720.     mov    dx,offset auxfile    ; user@host or print param field
  721.     call    strlen            ; get length into cl
  722.     push    cx            ; save address length
  723.     inc    cl            ; include disposition letter M or P
  724.     add    cl,' '            ; add ascii bias
  725.     mov    [di],cl            ; store in length field
  726.     inc    di
  727.     mov    byte ptr [di],'M'    ; mail the file
  728.     cmp    mailflg,2        ; REMOTE PRINT?
  729.     jne    sat5t2            ; ne = no
  730.     mov    byte ptr [di],'P'    ; say disposition is Print
  731. sat5t2:    inc    di
  732.     pop    cx            ; recover address length
  733.     jcxz    sat5tx            ; z = empty field
  734.     mov    si,dx            ; parameter field
  735.     cld
  736.     rep    movsb            ; append address text to field
  737. sat5tx:    ret
  738.  
  739. sat6t:    test    flags.attflg,atttype    ; can we send File Type attribute?
  740.     jz    sat6tx            ; z = no
  741.     mov    al,'"'            ; File Type attribute (")
  742.     cld
  743.     stosb
  744.     cmp    dtrans.xtype,0        ; Text?
  745.     jne    sat6t1            ; ne = no, likely Binary
  746.     mov    al,3+20h        ; three bytes follow
  747.     stosb
  748.     mov    al,'A'            ; A for ascii
  749.     stosb
  750.     mov    ax,'JM'            ; using Control-M and Control-J
  751.     stosw                ; as line delimiters
  752.     ret
  753. sat6t1:    mov    al,2+20h        ; two bytes follow
  754.     stosb
  755.     mov    ax,'8B'            ; "B8" = Binary, 8-bit byte literals
  756.     stosw
  757. sat6tx:    ret
  758.  
  759. sat7t:    test    flags.attflg,attchr    ; Character-set allowed?
  760.     jz    sat7tx            ; z = no
  761.     cmp    dtrans.xtype,1        ; Binary?
  762.     je    sat7tx            ; e = yes, no char-set stuff
  763.     mov    al,'*'            ; Encoding strategy
  764.     cld
  765.     stosb
  766.     mov    al,1+20h        ; length following, say one char
  767.     stosb
  768.     mov    al,'A'            ; assume normal Transparent
  769.     stosb
  770.     cmp    dtrans.xchset,0        ; is it transparent?
  771.     je    sat7tx            ; e = yes
  772.     mov    al,'C'            ; say transfer char-set encoding
  773.     dec    di            ; replace 'A' with 'C'
  774.     stosb
  775.     push    bx
  776.     mov    bl,dtrans.xchset    ; get def char set index
  777.     xor    bh,bh
  778.     shl    bx,1            ; count words
  779.     mov    bx,charids[bx+2]    ; bx points at set [length, string]
  780.     mov    al,[bx]            ; get length of ident string
  781.     mov    cl,al            ; copy to loop counter
  782.     xor    ch,ch
  783.     inc    al            ; add 'C' in attribute
  784.     add    al,20h            ; length of string + ascii bias
  785.     mov    byte ptr [di-2],al    ; length of attribute
  786.     push    si
  787.     mov    si,bx            ; ident string length byte
  788.     inc    si            ; text of ident string
  789.     cld
  790.     rep    movsb            ; copy to destination
  791.     pop    si
  792.     pop    bx
  793. sat7tx:    ret
  794.  
  795. SATTR    ENDP
  796.  
  797. ;    Send data
  798. ; Send main body of file, 'D' state
  799.  
  800. SDATA    PROC    NEAR
  801.     cmp    flags.cxzflg,0        ; interrupted?
  802.     je    sdata1            ; e = no
  803.     mov    sstate,'Z'        ; declare EOF, analyze interrupt there
  804.     ret
  805.  
  806. sdata1:    call    getbuf            ; get a buffer for sending
  807.     jnc    sdata2            ; nc = success
  808.     mov    al,windlow        ; earliest sequence number sent
  809.     mov    ah,maxtry        ; retry threshold
  810.     jmp    response        ; can't send, try getting responses
  811.  
  812. sdata2:    mov    [si].pktype,'D'        ; send Data packet
  813.     call    gtchr            ; fill buffer from file and encode
  814.     jc    sdata3            ; c = failure (no data/EOF, other)
  815.     cmp    [si].datlen,0        ; read any data?
  816.     je    sdata3            ; e = end of data, send 'Z' for EOF
  817.     call    sndpak            ; send the packet
  818.     inc    pktnum            ; next sequence number to send
  819.     and    pktnum,3fh        ; modulo 64
  820.     ret
  821.  
  822. sdata3:    call    bufrel            ; release unused buffer
  823.     mov    sstate,'Z'        ; at End of File, change to EOF state
  824.     ret
  825. SDATA    ENDP
  826.  
  827. ; Send EOF, 'Z' state
  828. SEOF    PROC    NEAR
  829.     call    getbuf            ; get a buffer for EOF packet
  830.     jnc    seof1            ; nc = got one, send 'Z' packet
  831.     mov    al,pktnum        ; seqnum of next packet to be used
  832.     dec    al            ; back up to last used
  833.     and    al,3fh            ;  sequence number of last sent pkt
  834.     mov    ah,maxtry        ; retry threshold
  835.     jmp    response        ; get responses to earlier packets
  836.  
  837. seof1:    xor    cx,cx            ; assume no data
  838.     cmp    flags.cxzflg,0        ; interrupted?
  839.     je    seof3            ; e = no, send normal EOF packet
  840.     call    intmsg            ; say interrupted
  841.     mov    encbuf,'D'        ; Use "D" for discard
  842.     mov    cx,1            ; set data size to 1
  843.     or    errlev,kssend        ; say send failed
  844.     or    fsta.xstatus,kssend+ksuser ; set status, failed + intervention
  845.     mov    kstatus,kssend+ksuser    ; global status
  846. seof3:    call    doenc            ; encode the packet (cx = count)
  847.     mov    [si].pktype,'Z'        ; EOF packet
  848.     call    sndpak            ; send the packet
  849.     jnc    seof6            ; nc = success
  850.     ret
  851.  
  852. seof6:    mov    al,[si].seqnum        ; packet just sent
  853.     mov    ah,maxtry        ; retry threshold
  854.     call    response        ; get reponse
  855.     jnc    seof7            ; nc = success
  856.     ret
  857.  
  858. seof7:    call    ackmsg            ; ACK, get/show any embedded message
  859.     inc    pktnum            ; next sequence number to send
  860.     and    pktnum,3fh        ; modulo 64
  861.                     ; Heuristic: ACK to 'Z' implies
  862.     mov    al,windlow        ;  ACKs to all previous packets
  863.     mov    ah,pktnum        ; loop limit, next packet
  864. seof8:    cmp    al,ah            ; done all "previous" packets?
  865.     je    seof8b            ; e = yes
  866.     call    pakptr            ; access packet for seqnum in AL
  867.     jc    seof8a            ; c = not in use
  868.     mov    si,bx            ; point to it
  869.     call    bufrel            ; release old buffer (synthetic ACK)
  870. seof8a:    inc    al            ; next slot
  871.     and    al,3fh
  872.     jmp    short seof8
  873. seof8b:                    ; end of Heuristic
  874.     mov    al,pktnum
  875.     mov    windlow,al        ; update windlow to next use
  876.     mov    ah,close2        ; close file
  877.     mov    bx,diskio.handle    ; file handle
  878.     int    dos
  879.     mov    filopn,0        ; no files open
  880.     cmp    flags.cxzflg,0        ; interrupted?
  881.     je    seof9            ; e = no
  882.     or    errlev,kssend        ; say send failed
  883.     or    fsta.xstatus,kssend+ksuser ; set status, failed + intervention
  884.     mov    kstatus,kssend+ksuser    ; global status
  885.     mov    ax,1            ; tell statistics this was a send
  886.     call    endtim
  887.     cmp    flags.cxzflg,'Z'    ; Control-Z seen?
  888.     jne    seof9            ; ne = no
  889.     mov    flags.cxzflg,0        ; clear the Control-Z
  890.     mov    auxfile,0        ; clear send-as/mail-address buffer
  891.     mov    sstate,'B'        ; file group complete state
  892.     ret
  893. seof9:    mov    ax,1            ; tell statistics this was a send
  894.     call    endtim
  895.     cmp    flags.cxzflg,0        ; interrupted?
  896.     je    seof10            ; e = no
  897.     cmp    flags.cxzflg,'X'    ; was Control-X signaled?
  898.     je    seof10            ; e = yes
  899.     mov    sstate,'E'         ; not ^X/^Z, must be ^C/^E
  900.     ret
  901. seof10:    mov    flags.cxzflg,0        ; clear the Control-X
  902.     cmp    mailflg,0        ; mail?
  903.     jne    seof11            ; e = yes, retain address in auxfile
  904.     mov    auxfile,0        ; clear send-as name
  905. seof11:    call    GTNFIL            ; get the next file
  906.     jc    seof12            ; c = no more files, do end of group
  907.     mov    filopn,1        ; file opened by gtnfil
  908.     mov    sstate,'F'        ; set state to file header send
  909.     ret
  910. seof12:    mov    sstate,'B'        ; set state to file group completed
  911.     ret
  912. SEOF    ENDP
  913.  
  914.  
  915. ; Send EOT
  916.  
  917. SEOT    PROC    NEAR
  918.     call    getbuf            ; get a buffer for sending
  919.     jnc    seot1            ; nc = got one
  920.     mov    al,pktnum        ; next sequence number to use
  921.     dec    al            ; back up to last used
  922.     and    al,3fh            ; get response to what was just sent
  923.     mov    ah,maxtry        ; retry threshold
  924.     jmp    response        ; get response, stay in this state
  925.  
  926. seot1:    mov    [si].pktype,'B'        ; End of Session packet
  927.     call    sndpak            ; send the packet
  928.     jnc    seot2            ; nc = sucess
  929.     ret
  930. seot2:    mov    al,pktnum        ; sequence number just sent
  931.     mov    ah,maxtry        ; retry threshold
  932.     call    response        ; get a response to it
  933.     jnc    seot3            ; nc = success
  934.     ret
  935. seot3:    call    ackmsg            ; get/show any embedded message
  936.     inc    pktnum            ; next sequence number to use
  937.     and    pktnum,3fh        ; modulo 64
  938.     mov    sstate,'C'        ; set state to file completed
  939.     ret
  940. SEOT    ENDP
  941.  
  942. ; Get response to seqnum in AL, retry AH times if necessary.
  943. ; Success: return carry clear and response data in rpacket
  944. ; Failure: return carry set and new state in sstate, will send Error packet
  945. ; Changes AX, BX, CX
  946. response proc    near
  947.     mov    tempseq,al        ; target sequence number
  948.     mov    retry,ah        ; retry threshold
  949.     mov    rpacket.numtry,0    ; no receive retries yet
  950. resp1:    mov    ah,rpacket.numtry    ; number of attempts in this routine
  951.     cmp    ah,retry        ; done enough?
  952.     ja    resp3            ; yes, feign a timeout
  953.     push    si            ; preserve regular packet pointer
  954.     mov    si,offset rpacket    ; address of receive packet structure
  955.     call    rpack            ; get a packet
  956.     pop    si
  957.     jnc    resp4            ; nc = success
  958.     cmp    flags.cxzflg,'C'    ; Control-C typed?
  959.     je    resp2            ; e = yes, quit
  960.     cmp    flags.cxzflg,'E'    ; Control-E typed?
  961.     jne    resp3            ; ne = no
  962. resp2:    mov    sstate,'E'        ; change to Error state
  963.     stc                ; return failure
  964.     ret
  965.  
  966. resp3:    inc    rpacket.numtry        ; no packet received, resend oldest
  967.     mov    al,windlow        ; get oldest sequence number
  968. resp3a:    call    pakptr            ; get packet pointer to seqnum in AL
  969.     jnc    resp3b            ; nc = ok, sequence number is in use
  970.     clc                ; packet not in use, simulate success
  971.     ret
  972.  
  973. resp3b:    push    si            ; resend oldest packet
  974.     dec    numpkt            ; a retry is not a new packet sent
  975.     mov    si,bx            ; packet pointer, from pakptr
  976.     call    cntretry        ; count retries, sense ^C/^E
  977.     jnc    resp3c            ; nc = ok to continue
  978.     pop    si            ; clean stack
  979.     ret                ; ^C/^E encountered, change states
  980.  
  981. resp3c:    mov    al,[si].numtry        ; times this packet was retried
  982.     cmp    al,retry        ; reached the limit?
  983.     jbe    resp3d            ; be = no, can do more sends
  984.     pop    si            ; clean stack
  985.     mov    dx,offset erms17    ; to many retries
  986.     jmp    giveup            ; abort with msgs to local and remote
  987.  
  988. resp3d:    mov    rpacket.numtry,0
  989.     call    sndpak            ; resend the packet
  990.     pop    si            ; clean stack
  991.     jnc    resp1            ; nc = success, retry getting response
  992.     ret
  993.  
  994. resp4:    call    acknak            ; got packet, get kind of response
  995.     or    al,al            ; ACK in window?
  996.     jz    resp8            ; z = yes
  997.     cmp    al,1            ; NAK in window?
  998.     je    resp6            ; e = yes, repeat pkt
  999.     cmp    al,3            ; NAK out of window?
  1000.     je    resp5            ; e = yes, repeat packet
  1001.     cmp    al,4            ; ACK to inactive packet?
  1002.     jne    resp4e            ; ne = no
  1003. ;;
  1004.     jmp    resp3            ; old ACK, resend oldest pkt
  1005. ; the above is to accomodate "book Kermits", not a good strategy, but...
  1006. ;;    inc    rpacket.numtry        ; count tries on reception
  1007. ;;    jmp    resp1            ; e = yes, retry reception
  1008. resp4e:    cmp    al,5            ; NAK to inactive packet?
  1009.     jne    resp4a            ; ne = no, leaves "other" types
  1010.     jmp    resp1            ; ignore NAK, try again
  1011.                     ; other packet types
  1012. resp4a:    cmp    rpacket.pktype,'M'    ; Message packet?
  1013.     jne    resp4b            ; ne = no
  1014.     push    si
  1015.     mov    si,offset rpacket
  1016.     call    msgmsg            ; display it and discard
  1017.     pop    si
  1018.     jmp    resp1            ; retry getting an ACK
  1019.  
  1020. resp4b:    cmp    rpacket.pktype,'E'    ; Error packet?
  1021.     jne    resp4c            ; ne = no
  1022.     jmp    error
  1023.  
  1024. resp4c:    mov    dx,offset erms16    ; unknown packet type
  1025.     jmp    giveup
  1026.  
  1027. resp5:    cmp    trans.windo,1        ; is windowing off?
  1028.     je    resp5a            ; e = yes, use old heuristic
  1029.     call    nakout            ; NAK rcvd outside window, resend all
  1030.     inc    rpacket.numtry        ; count this as an internal retry
  1031.     jmp    resp1            ; get more responses
  1032.     
  1033. resp5a:    mov    al,rpacket.seqnum    ; NAK rcvd outside window, say NAK is
  1034.     dec    al            ;  ACK for preceeding pkt to satisfy
  1035.     and    al,3fh            ;  non-windowing Kermits
  1036.     mov    rpacket.seqnum,al    ; force seqnum to preceed this NAK
  1037.     mov    rpacket.pktype,'Y'    ; force packet to look like an ACK
  1038.     jmp    short resp4        ; reanalyze our status
  1039.  
  1040. resp6:    mov    al,rpacket.seqnum    ; single sequence number being NAK'd
  1041.     inc    rpacket.numtry        ; count this as an internal retry
  1042.     jmp    resp3a            ; repeat that packet
  1043.  
  1044.                     ; ACK in window
  1045. resp8:    mov    al,windlow        ; try to purge all ack'd packets
  1046.     call    pakptr            ; get buffer pointer for it into BX
  1047.     jc    resp8a            ; c = buffer not in use
  1048.     cmp    [bx].ackdone,0        ; ack'd yet?
  1049.     je    resp8a            ; e = no, stop here
  1050.     mov    si,bx
  1051.     call    bufrel            ; ack'd active buffer, release si
  1052.     inc    al            ; rotate window
  1053.     and    al,3fh
  1054.     mov    windlow,al
  1055.     jmp    short resp8        ; keep purging
  1056.  
  1057. resp8a:    mov    al,tempseq        ; check for our desired seqnum
  1058.     mov    rpacket.numtry,0
  1059.     cmp    al,rpacket.seqnum    ; is this the desired object?
  1060.     je    resp8b            ; e = yes
  1061.     jmp    resp1            ; no, read another response
  1062. resp8b:    clc                ; return success
  1063.     ret
  1064. response endp
  1065.  
  1066. ; Send packet, with retries
  1067. ; Enter with SI pointing to packet structure. Success returns carry clear.
  1068. ; Failure, after retries, returns carry set and perhaps a new sstate.
  1069. sndpak    proc    near            
  1070.     inc    numpkt            ; number packets sent
  1071.     call    pktsize            ; report packet qty and size
  1072.     mov    sndcnt,0        ; send retry counter, internal
  1073.     cmp    [si].pktype,'I'        ; do not show windows for I/S
  1074.     je    sndpa3
  1075.     cmp    [si].pktype,'S'
  1076.     je    sndpa3
  1077.     call    winpr            ; show windows in use
  1078.  
  1079. sndpa3:    call    spack            ; send the packet
  1080.     jc    sndpa4            ; nc = failure
  1081.     ret                ; return success
  1082.  
  1083. sndpa4:    push    ax            ; failure, do several retries
  1084.     mov    ax,100            ; wait 0.1 seconds
  1085.     call    pcwait
  1086.     call    cntretry        ; show retries on screen
  1087.     inc    sndcnt            ; internal retry counter
  1088.     mov    al,sndcnt
  1089.     cmp    al,maxtry        ; reached retry limit?
  1090.     pop    ax
  1091.     jbe    sndpa3            ; be = no, can do more retries
  1092.     mov    dx,offset erms24    ; cannot send packet
  1093.     jmp    giveup            ; set carry, change state
  1094. sndpak    endp
  1095.  
  1096. ; Check the packet rpacket for an ACK, NAK, or other.
  1097. ; Returns in CX:
  1098. ; 0 for ACK to active packet (marks buffer as ACK'd, may rotate window)
  1099. ; 1 for NAK to active packet
  1100. ; 2 for an unknown packet type
  1101. ; 3 for NAK outside the window
  1102. ; 4 for other ACKs (out of window, to inactive packet)
  1103. ; 5 for NAKs in window to inactive packets.
  1104. ; Timeout packet (type 'T') is regarded as a NAK out of the window.
  1105. ; Marks pkts ACK'd but clears packets only when they rotate below the window.
  1106. ; Uses registers AX ,BX, and CX.
  1107. ACKNAK    PROC    NEAR
  1108.     mov    al,rpacket.seqnum    ; this packet's sequence number
  1109.     mov    ah,rpacket.pktype    ; and packet type
  1110.     cmp    ah,'Y'            ; ack packet?
  1111.     jne    ackna2            ; ne = no
  1112.     call    pakptr            ; is it for an active buffer?
  1113.     jnc    ackna1            ; nc = yes
  1114.     mov    al,4            ; say ACK for inactive pkt
  1115.     clc
  1116.     ret
  1117. ackna1:    mov    [bx].ackdone,1        ; say packet has been acked
  1118.     cmp    al,windlow        ; ok to rotate window?
  1119.     jne    ackna1a            ; ne = no
  1120.     inc    windlow            ; rotate window one slot
  1121.     and    windlow,3fh
  1122.     push    si            ; save pointer
  1123.     mov    si,bx            ; packet pointer from pakptr
  1124.     call    bufrel            ; release buffer for SI
  1125.     pop    si
  1126. ackna1a:cmp    rpacket.datlen,0    ; any data in the ACK?
  1127.     je    ackna1c            ; e = no
  1128.     cmp    sstate,'F'        ; in file header state?
  1129.     je    ackna1c            ; e = yes, no protocol char
  1130.     mov    bx,rpacket.datadr    ; look for data in the ACK
  1131.     mov    ah,[bx]
  1132.     cmp    ah,'C'            ; Control-C message?
  1133.     je    ackna1b            ; e = yes
  1134.     cmp    ah,'X'            ; quit this file?
  1135.     je    ackna1b            ; e = yes
  1136.     cmp    ah,'Z'            ; quit this file group?
  1137.     jne    ackna1c
  1138. ackna1b:mov    flags.cxzflg,ah        ; store here
  1139.     mov    sstate,'Z'        ; move to end of file state
  1140.     mov    rstate,'Z'
  1141. ackna1c:xor    al,al            ; ack'd ok
  1142.     clc
  1143.     ret
  1144.                     ; not an ACK
  1145. ackna2:    cmp    ah,'N'            ; NAK?
  1146.     je    ackna3            ; e = yes
  1147.     cmp    ah,'T'            ; Timeout?
  1148.     je    ackna3a            ; e = yes, same as NAK out of window
  1149.     mov    al,2            ; else say unknown type
  1150.     clc
  1151.     ret
  1152.  
  1153. ackna3:    inc    fsta.nakrcnt        ; count received NAK for statistics
  1154.     push    si
  1155.     mov    si,offset rpacket
  1156.     call    chkwind            ; check if seqnum is in window
  1157.     pop    si
  1158.     jcxz    ackna3b            ; z = in window
  1159. ackna3a:mov    al,3            ; say NAK out of window
  1160.     clc
  1161.     ret
  1162.  
  1163. ackna3b:push    bx            ; NAK in window, is pkt still active?
  1164.     call    pakptr            ; seqnum for an active packet?
  1165.     pop    bx
  1166.     jc    ackna4            ; c = no, ignore NAK as "dead NAK" 
  1167.     mov    al,1            ; say NAK for active packet
  1168.     clc
  1169.     ret
  1170.  
  1171. ackna4:    mov    al,5            ; dead NAKs
  1172.     clc
  1173.     ret
  1174. ACKNAK    ENDP
  1175.  
  1176. nakout    proc    near            ; NAK out of window, resend all pkts
  1177.     mov    al,windlow        ; start here
  1178.     mov    ah,al
  1179.     add    ah,trans.windo
  1180.     and    ah,3fh            ; top of window+1
  1181. nakout1:call    pakptr            ; get pkt pointer for seqnum in al
  1182.     jc    nakout4            ; c = slot not in use
  1183.     mov    si,bx            ; bx is packet pointer from pakptr
  1184.     cmp    [si].ackdone,0        ; has packet has been acked?
  1185.     jne    nakout4            ; ne = yes
  1186.     cmp    al,windlow        ; count retries only for windlow
  1187.     jne    nakout2            ; ne = not windlow
  1188.     call    cntretry        ; count retries
  1189.     jc    nakout3            ; c = quit now
  1190.     mov    cl,[si].numtry
  1191.     cmp    cl,retry        ; reached the limit yet?
  1192.     ja    nakout3            ; a = yes, quit
  1193. nakout2:push    ax
  1194.     call    pktsize            ; report packet size
  1195.     call    sndpak            ; resend the packet
  1196.     pop    ax
  1197.     jmp    short nakout4        ; do next packet
  1198.  
  1199. nakout3:call    bufclr            ; error exit
  1200.     mov    dx,offset erms17    ; too many retries
  1201.     jmp    giveup            ; too many retries
  1202.  
  1203. nakout4:inc    al            ; next sequence number
  1204.     and    al,3fh
  1205.     cmp    al,ah            ; sent all packets?
  1206.     jne    nakout1            ; ne = no, repeat more packets
  1207.     ret                ; return to do another data send
  1208. nakout    endp
  1209.  
  1210. cntretry proc    near            ; count retries, sense user exit
  1211.     cmp    flags.cxzflg,'C'    ; user wants abrupt exit?
  1212.     je    cntre2            ; e = yes
  1213.     cmp    flags.cxzflg,'E'    ; Error type exit?
  1214.     je    cntre2            ; e = yes
  1215.     inc    fsta.pretry        ; increment the number of retries
  1216.     inc    [si].numtry        ; for this packet too
  1217.     test    flags.remflg,dserver    ; server mode?
  1218.     jnz    cntre3            ; nz = yes, writing to their screen
  1219.     cmp    flags.xflg,1        ; writing to screen?
  1220.     je    cntre1            ; e = yes, skip this
  1221. cntre3:    cmp    fmtdsp,0        ; formatted display?
  1222.     je    cntre1            ; e = no
  1223.     call    rtmsg            ; display retries
  1224. cntre1:    clc
  1225.     ret
  1226. cntre2:    mov    sstate,'E'        ; abort, shared by send and receive
  1227.     mov    rstate,'E'        ; abort
  1228.     stc
  1229.     ret
  1230. cntretry endp
  1231.  
  1232. ; Display message in ACK's to F and D packets. Requires a leading protocol
  1233. ; char for D packets and expects message to be encoded.
  1234. ackmsg    proc near
  1235.     test    flags.remflg,dquiet    ; quiet display mode?
  1236.     jnz    ackmsgx            ; nz = yes, don't write to screen
  1237.     cmp    rpacket.datlen,0    ; any embedded message?
  1238.     je    ackmsgx            ; e = no
  1239.     cmp    sstate,'F'        ; file header state?
  1240.     je    ackmsg1            ; e = yes, no leading protocol char
  1241.     cmp    rpacket.datlen,1    ; D packet, skip protocol char
  1242.     je    ackmsgx            ; e = no displayable information
  1243. ackmsg1:push    si
  1244.     push    ax
  1245.     push    dx
  1246.     call    cxmsg            ; clear message space in warning area
  1247.     mov    word ptr decbuf,0    ; clear two bytes
  1248.     mov    si,offset rpacket    ; source address
  1249.     call    dodec            ; decode message, including X/Z/other
  1250.     mov    dx,offset decbuf+1    ; decoded data
  1251.     cmp    sstate,'F'        ; file header state?
  1252.     jne    ackmsg3            ; ne = no
  1253.     push    dx
  1254.     mov    dx,offset infms5    ; give a leader msg
  1255.     call    prtasz
  1256.     pop    dx
  1257.     dec    dx            ; start with first message char
  1258. ackmsg2:mov    bx,dx
  1259.     cmp    byte ptr [bx],' '    ; space?
  1260.     jne    ackmsg3            ; ne = no
  1261.     inc    dx            ; next msg char
  1262.     jmp    short ackmsg2        ; continue stripping off spaces
  1263. ackmsg3:call    prtasz            ; display message
  1264.     mov    ah,prstr
  1265.     mov    dx,offset crlf
  1266.     int    dos
  1267.     pop    dx
  1268.     pop    ax
  1269.     pop    si
  1270. ackmsgx:mov    rpacket.datlen,0
  1271.     ret
  1272. ackmsg    endp
  1273.  
  1274. ; newfn    -- move replacement name from buffer auxfile to buffer encbuf
  1275.  
  1276. newfn    proc    near
  1277.     push    si
  1278.     push    di
  1279.     cmp    auxfile,0        ; sending file under different name?
  1280.     je    newfn4            ; e = no, so don't give new name
  1281.     mov    si,offset auxfile    ; source field
  1282.     mov    di,offset fsta.xname    ; statistics external name area
  1283.     call    strcpy
  1284.     test    flags.remflg,dquiet    ; quiet display mode?
  1285.     jnz    newfn2            ; nz = yes, do not write to screen
  1286.     mov    dx,offset asmsg        ; display ' as '
  1287.     cmp    mailflg,0        ; mail?
  1288.     je    newfn1            ; e = no
  1289.     mov    dx,offset mailto    ; display ' To: '
  1290. newfn1:    call    prtasz            ; display asciiz msg
  1291.     cmp    mailflg,0        ; mail?
  1292.     je    newfn2            ; e = no
  1293.     mov    dx,offset auxfile    ; get name
  1294.     call    prtasz            ; display asciiz string
  1295.     jmp    short newfn4        ; don't replace filename
  1296. newfn2:    mov    si,offset auxfile    ; external name
  1297.     mov    di,offset encbuf
  1298.     call    strcpy            ; put into encoder buffer
  1299.     test    flags.remflg,dquiet    ; quiet display mode (should we print)?
  1300.     jnz    newfn5            ; nz = yes
  1301.     mov    dx,si
  1302.     call    prtasz            ; display external name
  1303. newfn4:    test    flags.remflg,dserial    ; serial display mode?
  1304.     jz    newfn5            ; z = no
  1305.     mov    dx,offset crlf        ; start with cr/lf for serial display
  1306.     mov    ah,prstr
  1307.     int    dos
  1308. newfn5:    pop    di
  1309.     pop    si
  1310.     ret
  1311. newfn    endp
  1312.  
  1313. ; This routine sets up the data for the response to an Init packet
  1314. ; trans.rxxx are items which have been negotiated.
  1315. ; Lines marked ;M energize the second CAPAS byte. Leave them as comments
  1316. ; because earlier versions of MS Kermit (and C Kermit) are confused by it
  1317. ; (failed to decode bit saying second CAPAS byte follows and thus lose sync).
  1318. ; Enter with SI = pktinfo pointer
  1319. ; Returns [si].datlen = length of data field, with packet buffer filled in.
  1320. RPAR    PROC    NEAR
  1321.     push    ax
  1322.     push    bx
  1323.     mov    bx,[si].datadr        ; data field address
  1324.     mov    al,trans.rpsiz        ; receive packet size
  1325.     add    al,' '            ; add a space to make it printable
  1326.     mov    [bx],al            ; put it in the packet
  1327.     inc    bx            ; 1
  1328.     mov    al,trans.rtime        ; receive packet time out
  1329.     add    al,' '
  1330.     mov    [bx],al
  1331.     inc    bx            ; 2
  1332.     mov    al,trans.rpad        ; number of padding chars
  1333.     add    al,' '
  1334.     mov    [bx],al
  1335.     inc    bx            ; 3
  1336.     mov    al,trans.rpadch        ; padding char
  1337.     add    al,40h            ; Uncontrol it
  1338.     and    al,7FH
  1339.     mov    [bx],al
  1340.     inc    bx            ; 4
  1341.     mov    al,trans.reol        ; EOL char
  1342.     add    al,' '
  1343.     mov    [bx],al
  1344.     inc    bx            ; 5
  1345.     mov    al,trans.rquote        ; quote char
  1346.     mov    [bx],al
  1347.     inc    bx            ; 6
  1348.     mov    al,trans.ebquot        ; 8-bit quote char
  1349.     mov    [bx],al
  1350.     inc    bx            ; 7
  1351.     mov    al,trans.chklen        ; Length of checksum
  1352.     add    al,'0'            ; make into a real digit
  1353.     mov    [bx],al
  1354.     inc    bx            ; 8
  1355.     mov    al,trans.rptq        ; repeat quote char
  1356.     or    al,al            ; null means none
  1357.     jnz    rpar0
  1358.     mov    al,' '            ; send a blank instead
  1359. rpar0:    mov    [bx],al
  1360.     inc    bx            ; 9
  1361.     mov    al,2            ; CAPAS, bit1 = can do long packets
  1362.     cmp    flags.attflg,0        ; allowing attributes packets?
  1363.     je    rpar1            ; e = no
  1364.     or    al,8            ; bit #3, can do file attributes
  1365. rpar1:    or    al,4            ; bit #4 can do windows
  1366.     add    al,20h            ; apply tochar() to byte
  1367. ;M    or    al,1            ; say second CAPAS byte follows
  1368.     mov    [bx],al
  1369.     inc    bx            ; 10
  1370.                     ; additional CAPAS go in here
  1371. ;M    mov    byte ptr [bx],20h+20h    ; Allow M (message) pkts, (#6, bit5)
  1372. ;M    inc    bx            ; 11
  1373.     mov    al,trans.windo        ; number of active window slots (1-31)
  1374.     add    al,20h            ; apply tochar()
  1375.     mov    [bx],al
  1376.     inc    bx
  1377.     push    dx            ; save reg
  1378.     mov    ax,trans.rlong        ; longest packet which we can receive
  1379.     xor    dx,dx            ; clear extended part for division
  1380.     div    ninefive        ; divide by 95. quo = ax, rem = dx
  1381.     add    al,20h            ; apply tochar() to quotient
  1382.     mov    [bx],al
  1383.     inc    bx
  1384.     add    dl,20h            ; apply tochar() to remainder
  1385.     mov    [bx],dl
  1386.     pop    dx            ; restore regs
  1387.     inc    bx
  1388.     sub    bx,[si].datadr        ; end minus beginning = length
  1389.     mov    [si].datlen,bx        ; length of rpar data in packet
  1390.     pop    bx
  1391.     pop    ax
  1392.     ret
  1393. RPAR    ENDP
  1394.  
  1395. ; Set maximum capabilities
  1396. ; dtrans are the defaults (which the user can modify), trans are negotiated
  1397. ; and active values.
  1398. SPARMAX    PROC    NEAR
  1399.     push    ax
  1400.     mov    al,dtrans.spsiz        ; [1] regular packet size MAXL
  1401.     mov    trans.spsiz,al
  1402.     mov    al,dtrans.stime        ; [2] send timeout value TIME
  1403.     mov    trans.rtime,al
  1404.     mov    al,dtrans.spad        ; [3] send padding count NPAD
  1405.     mov    trans.spad,al
  1406.     mov    al,dtrans.spadch    ; [4] send padding character PADC
  1407.     mov    trans.spadch,al
  1408.     mov    al,dtrans.seol        ; [5] EOL character EOL
  1409.     mov    trans.seol,al
  1410.     mov    al,dtrans.squote    ; [6] control quote character QCTL
  1411.     mov    trans.squote,al
  1412.     push    bx            ; [7] 8-bit quote character QBIN
  1413.     mov    bx,portval
  1414.     mov    al,[bx].parflg        ; get our parity flag
  1415.     cmp    al,parnon        ; parity of none?
  1416.     je    spmax1            ; e = yes, reset 8 bit quote character
  1417.     mov    trans.ebquot,dqbin    ; we want quoting, active
  1418.     mov    dtrans.ebquot,dqbin    ; we want quoting, our default
  1419.     jmp    short spmax2
  1420. spmax1:    mov    trans.ebquot,'Y'    ; say will quote upon request
  1421.     mov    dtrans.ebquot,'Y'    ; and our default
  1422. spmax2:    pop    bx
  1423.     mov    al,dtrans.chklen    ; [8] initial checksum type CHKT
  1424.     mov    trans.chklen,al
  1425.     mov    al,dtrans.rptq        ; [9] repeat prefix character REPT
  1426.     mov    trans.rptq,al
  1427.     mov    trans.capas,8+4        ; [10-11] capas bitmap CAPAS
  1428.     mov    trans.capas+1,20h    ;  [11] CAPAS+1, Message pkts
  1429.     mov    al,dtrans.windo        ; [12] window size WINDO
  1430.     mov    trans.windo,al
  1431.     mov    ax,dtrans.slong        ; [13-14] long packet send length,
  1432.     mov    trans.slong,ax        ;  MAXLX1 and MAXLX2
  1433.                     ;
  1434.     mov    al,dtrans.rpsiz        ; max regular packet we can receive
  1435.     mov    trans.rpsiz,al        ;  for window of one slot
  1436.     mov    ax,dtrans.rlong        ; max long packet we can receive
  1437.     mov    trans.rlong,ax        ;  for window of one slot
  1438.     pop    ax
  1439.     ret
  1440. SPARMAX    ENDP
  1441.  
  1442. ; This routine reads in all the send init packet information
  1443. ; Enter with SI = pktinfo address, [si].datlen = packet length
  1444. ; All regs preserved except AX. 
  1445. ; dtrans.xxx are the default parameters if the other side says nothing
  1446. ; trans.sxxx are the active negotiated parameters we will use.
  1447. SPAR    PROC    NEAR
  1448.     push    ax            ; set min defaults for no host data
  1449.     mov    trans.spsiz,80        ; [1] regular packet size MAXL
  1450.     mov    al,dtrans.stime        ; get user selected stime
  1451.     mov    trans.stime,al        ; [2] send timeout value TIME
  1452.     mov    trans.spad,0        ; [3] send padding count NPAD
  1453.     mov    al,dtrans.spadch    ; [4] send padding character PADC
  1454.     mov    trans.spadch,al
  1455.     mov    trans.seol,CR        ; [5] EOL character EOL
  1456.  
  1457.     mov    trans.squote,'#'    ; [6] control quote character QCTL
  1458.     mov    al,dtrans.ebquot    ; [7] 8-bit quote character QBIN
  1459.     mov    trans.ebquot,al        ;  use default to include our parity
  1460.                     ; end of the basic items
  1461.     mov    al,dtrans.chklen    ; [8] initial checksum type CHKT
  1462.     mov    trans.chklen,al
  1463.     xor    ax,ax
  1464.     mov    trans.rptq,al        ; [9] repeat prefix character REPT
  1465.     mov    trans.capas,al        ; [10-11] capas bitmap CAPAS
  1466.     mov    trans.capas+1,al
  1467.     mov    trans.windo,1        ; [12] window size WINDO
  1468.     mov    al,trans.spsiz
  1469.     mov    trans.slong,ax        ; [13-14] long packet send length,
  1470.                     ;  MAXLX1 and MAXLX2
  1471.                     ; start negotiations
  1472.     push    si            ; pktinfo structure pointer
  1473.     mov    ax,[si].datlen        ; length of received data
  1474.     mov    ah,al            ; number of args is now in ah
  1475.     mov    si,[si].datadr        ; pointer to received data
  1476.     cld
  1477.     or    ah,ah            ; [1] MAXL  any data?
  1478.     jg    spar1a            ; g = yes
  1479.     jmp    sparx1
  1480. spar1a:    lodsb                ; get the max regular packet size
  1481.     dec    ah            ; ah = bytes remaining to be examined
  1482.     sub    al,' '            ; subtract ascii bias
  1483.     jnc    spar1b            ; c = old C Kermit error
  1484.     mov    al,spmax
  1485. spar1b:    cmp    al,dtrans.spsiz        ; user limit is less?
  1486.     jbe    spar1c            ; be = no
  1487.     mov    al,dtrans.spsiz        ; replace with our lower limit
  1488. spar1c:    cmp    al,spmin        ; below the minimum?
  1489.     jge    spar1d            ; ge = no
  1490.     mov    al,spmin
  1491. spar1d:    cmp    al,spmax        ; or above the maximum?
  1492.     jle    spar1e            ; le = no
  1493.     mov    al,spmax
  1494. spar1e:    mov    trans.spsiz,al        ; save it
  1495.     push    ax
  1496.     xor    ah,ah            ; set long packet to regular size
  1497.     mov    trans.slong,ax
  1498.     pop    ax
  1499.  
  1500.     or    ah,ah            ; [2] TIME  more data?
  1501.     jg    spar2a            ; g = yes
  1502.     jmp    sparx1
  1503. spar2a:    lodsb                ; get the timeout value
  1504.     dec    ah
  1505.     sub    al,' '            ; subtract a space
  1506.     jge    spar2b            ; must be non-negative
  1507.     xor    al,al            ; negative, so use zero
  1508. spar2b:    cmp    al,trans.rtime        ; same as other side's timeout
  1509.     jne    spar2c            ; ne = no
  1510.     inc    al            ; yes, but make it a little different
  1511. spar2c:    cmp    dtrans.stime,dstime    ; is current value the default?
  1512.     je    spar2d            ; e = yes, else user value overrides
  1513.     mov    al,dtrans.stime        ; get user selected stime
  1514. spar2d:    mov    trans.stime,al        ; save it
  1515.                     ;
  1516.     or    ah,ah            ; [3] NPAD  more data?
  1517.     jg    spar3a            ; g = yes
  1518.     jmp    sparx1
  1519. spar3a:    lodsb                ; get the number of padding chars
  1520.     dec    ah
  1521.     sub    al,' '
  1522.     jge    spar3b            ; must be non-negative
  1523.     xor    al,al
  1524. spar3b:    mov    trans.spad,al        ; number of padding chars to send
  1525.                     ;
  1526.     or    ah,ah            ; [4] PADC  more data?
  1527.     jg    spar4a            ; g = yes
  1528.     jmp    sparx1
  1529. spar4a:    lodsb                ; get the padding char
  1530.     dec    ah
  1531.     add    al,40h            ; remove ascii bias
  1532.     and    al,7FH
  1533.     cmp    al,del            ; Delete?
  1534.     je    spar4b            ; e = yes, then it's OK
  1535.     cmp    al,31            ; control char?
  1536.     jbe    spar4b            ; be = yes, then OK
  1537.     xor    al,al            ; no, use null
  1538. spar4b:    mov    trans.spadch,al
  1539.                     ;
  1540.     or    ah,ah            ; [5] EOL  more data?
  1541.     jg    spar5a            ; g = yes
  1542.     jmp    sparx1
  1543. spar5a:    lodsb                ; get the EOL char
  1544.     dec    ah
  1545.     sub    al,' '
  1546.     cmp    al,31            ; control char?
  1547.     jbe    spar5b            ; le = yes, then use it
  1548.     mov    al,cr            ; else use the default
  1549. spar5b:    mov    trans.seol,al        ; EOL char to be used
  1550.                     ;
  1551.     or    ah,ah            ; [6] QCTL  more data?
  1552.     jg    spar6a            ; g = yes
  1553.     jmp    sparx1
  1554. spar6a:    lodsb                ; get the quote char
  1555.     dec    ah
  1556.     cmp    al,' '            ; less than a space?
  1557.     jge    spar6b            ; ge = no
  1558.     mov    al,dsquot        ; yes, use default
  1559. spar6b:    cmp    al,7eh            ; must also be less than a tilde
  1560.     jbe    spar6c            ; be = is ok
  1561.     mov    al,dsquot        ; else use default
  1562. spar6c:    mov    trans.squote,al
  1563.                     ;
  1564.     or    ah,ah            ; [7] QBIN  more data?
  1565.     jg    spar7a            ; g = yes
  1566.     jmp    sparx1
  1567. spar7a:    lodsb                ; get other side's 8-bit quote request
  1568.     dec    ah
  1569.     call    doquo            ; and set quote char
  1570.                     ;
  1571.     or    ah,ah            ; [8] CHKT  more data?
  1572.     jg    spar8a            ; a = yes
  1573.     jmp    sparx1
  1574. spar8a:    lodsb                ; get other side's checksum length
  1575.     dec    ah
  1576.     call    dochk            ; determine what size to use
  1577.                     ;
  1578.     or    ah,ah            ; [9] REPT  more data?
  1579.     jg    spar9a            ; g = yes
  1580.     jmp    sparx1
  1581. spar9a:    lodsb                ; get other side's repeat count prefix
  1582.     dec    ah
  1583.     call    dorpt            ; negotiate prefix into trans.rptq
  1584.                     ;
  1585.     or    ah,ah            ; [10] CAPAS  more data?
  1586.     ja    spar10a            ; g = yes
  1587.     jmp    sparx1
  1588. spar10a:lodsb                ; get CAPAS bitmap from other side
  1589.     dec    ah
  1590.     and    al,not (1)        ; remove least significant bit
  1591.     sub    al,20h            ; apply unchar()
  1592.     mov    trans.capas,al        ; store result in active byte
  1593.                     ;
  1594. spar11:    or    ah,ah            ; [11] CAPAS+  more data?
  1595.     ja    spar11a            ; a = yes
  1596.     jmp    sparx1
  1597. spar11a:test    byte ptr [si-1],1    ; is CAPAS byte continued to another?
  1598.     jz    spar12            ; z = no
  1599.     lodsb                ; get 2nd CAPAS bitmap from other side
  1600.     dec    ah
  1601.     and    al,not (1)        ; remove least significant bit
  1602.     sub    al,20h            ; apply unchar(). Store nothing
  1603.     mov    trans.capas+1,al    ; keep second CAPAS byte
  1604.  
  1605. spar11c:or    ah,ah            ; [11] CAPAS++  more data?
  1606.     ja    spar11d            ; a = yes
  1607.     jmp    sparx1
  1608. spar11d:test    byte ptr [si-1],1    ; is CAPAS byte continued to another?
  1609.     jz    spar12            ; z = no
  1610.     lodsb                ; 3rd et seq CAPAS bitmaps
  1611.     dec    ah
  1612.     and    al,not (1)        ; remove least significant bit
  1613.     sub    al,20h            ; apply unchar(). Store nothing
  1614.     jmp    short spar11c        ; seek more CAPAS bytes
  1615.                     ;
  1616. spar12:    or    ah,ah            ; [12] WINDO  more data?
  1617.     jg    spar12a            ; g = yes
  1618.     jmp    sparx1            ; exit spar
  1619. spar12a:lodsb                ; get other side's window size
  1620.     dec    ah
  1621.     sub    al,20h            ; apply unchar()
  1622.     call    dewind            ; negotiate window size
  1623.                     ;
  1624.     cmp    ah,2            ; [13-14] MAXL (long packet needs 2)
  1625.     jge    spar13a            ; ge = enough data to look at
  1626.     push    ax            ; make long same size as regular
  1627.     xor    ah,ah
  1628.     mov    al,trans.spsiz        ; normal packet size
  1629.     mov    trans.slong,ax        ; assume not using long packets
  1630.     pop    ax            ; recover ah
  1631.     jmp    short sparx1        ; do final checks on packet length
  1632. spar13a:test    trans.capas,2        ; do they have long packet capability?
  1633.     jnz    spar13b            ; nz = yes
  1634.     jmp    short sparx1        ; no, skip following l-pkt len fields
  1635. spar13b:lodsb                ; long pkt length, high order byte
  1636.     push    ax            ; save ah
  1637.     sub    al,20h            ; apply unchar()
  1638.     xor    ah,ah
  1639.     mul    ninefive        ; times 95 to dx (high), ax (low)
  1640.     mov    trans.slong,ax        ; store high order part
  1641.     lodsb                ; long pkt length, low order byte
  1642.     sub    al,20h            ; apply unchar()
  1643.     xor    ah,ah
  1644.     add    ax,trans.slong        ; plus high order part
  1645.     mov    trans.slong,ax        ; store it
  1646.     or    ax,ax            ; if result is 0 then use regular pkts
  1647.     jnz    spar13c            ; non-zero, use what they want
  1648.     mov    al,trans.spsiz        ; else default to regular packet size
  1649.     xor    ah,ah
  1650.     mov    trans.slong,ax    ;  and ignore the CAPAS bit (no def 500 bytes)
  1651. spar13c:cmp    ax,dtrans.slong        ; longer than we want to do?
  1652.     jbe    spar13d            ; be = no
  1653.     mov    ax,dtrans.slong        ; limit to our longest sending size
  1654.     mov    trans.slong,ax        ; and use it
  1655. spar13d:pop    ax            ; recover ah
  1656.                     ; Windowing can further shrink pkts
  1657. sparx1:    push    cx            ; final packet size negotiations
  1658.     push    dx
  1659.     mov    ax,maxpack        ; our max buffer size
  1660.     mov    cl,trans.windo        ; number of active window slots
  1661.     xor    ch,ch
  1662.     jcxz    sparx2            ; 0 means 1, for safety here
  1663.     xor    dx,dx            ; whole buffer / # window slots
  1664.     div    cx            ; ax = longest windowed pkt possible
  1665.                     ; transmitter packet size
  1666. sparx2:    cmp    ax,trans.slong        ; our slots can be longer than theirs?
  1667.     ja    sparx2a            ; a = yes, use their shorter length
  1668.     mov    trans.slong,ax        ; no, use our shorter length
  1669. sparx2a:mov    cl,trans.spsiz        ; current regular pkt size
  1670.     xor    ch,ch
  1671.     cmp    cx,ax            ; is regular longer than window slot?
  1672.     jbe    sparx3            ; be = no
  1673.     mov    trans.spsiz,al        ; shrink regular to windowed size
  1674.                     ; receiver packet size
  1675. sparx3:    cmp    ax,dtrans.rlong        ; slot shorter than longest allowed?
  1676.     jae    sparx5            ; ae = no
  1677.     mov    trans.rlong,ax        ; long size we want to receive
  1678.     mov    cl,dtrans.rpsiz        ; regular packet size user limit
  1679.     xor    ch,ch
  1680.     cmp    cx,ax            ; is regular longer than window too?
  1681.     jbe    sparx4            ; be = no
  1682.     mov    cl,al            ; shrink regular to windowed size
  1683. sparx4:    mov    trans.rpsiz,cl        ; regular size we want
  1684. sparx5:    pop    dx
  1685.     pop    cx
  1686.     pop    si            ; saved at start of spar
  1687.     pop    ax
  1688.     ret
  1689. SPAR    ENDP
  1690.  
  1691. ; Set 8-bit quote character based on my capabilities and the other
  1692. ; Kermit's request. Quote if one side says Y and the other a legal char
  1693. ; or if both sides say the same legal char. Enter with AL = their quote char
  1694. DOQUO    PROC    NEAR
  1695.     cmp    dtrans.ebquot,'N'    ; we refuse to do 8-bit quoting?
  1696.     je    dq3            ; e = yes, do not quote
  1697.     cmp    al,'N'            ; 'N' = they refuse quoting?
  1698.     je    dq3            ; e = yes, do not quote
  1699.     cmp    dtrans.ebquot,'Y'    ; can we do it if requested?
  1700.     je    dq2            ; e = yes, use their char in al
  1701.     cmp    al,'Y'            ; 'Y' = they can quote if req'd?
  1702.     jne    dq1            ; ne = no, use their particular char
  1703.     mov    al,dtrans.ebquot    ; we want to use a particular char
  1704.     call    prechk            ;  and they said 'Y', check ours
  1705.     jc    dq3            ; c = ours is out of range, no quoting
  1706. dq1:    cmp    al,dtrans.ebquot    ; active quote vs ours, must match
  1707.     jne    dq3            ; ne = mismatch, no quoting
  1708. dq2:    mov    trans.ebquot,al        ; get active char, ours or theirs
  1709.     call    prechk            ; in range 33-62, 96-126?
  1710.     jc    dq3            ; c = out of range, do not quote
  1711.     cmp    al,trans.rquote        ; same prefix as control-quote?
  1712.     je    dq3            ; e = yes, don't do 8-bit quote
  1713.     cmp    al,trans.squote        ; same prefix control-quote?
  1714.     je    dq3            ; this is illegal too
  1715.     mov    trans.ebquot,al        ; remember what we decided on
  1716.     ret
  1717. dq3:    mov    trans.ebquot,'N'    ; quoting will not be done
  1718.     ret
  1719. DOQUO    ENDP
  1720.  
  1721. ; Check if prefix in AL is in the proper range: 33-62, 96-126. 
  1722. ; Return carry clear if in range, else return carry set.
  1723. prechk:    cmp    al,33
  1724.     jb    prechk2            ; b = out of range
  1725.     cmp    al,62
  1726.     jbe    prechk1            ; be = in range 33-62
  1727.     cmp    al,96
  1728.     jb    prechk2            ; b = out of range
  1729.     cmp    al,126
  1730.     ja    prechk2            ; a = out of range 96-126
  1731. prechk1:clc                ; carry clear for in range
  1732.     ret
  1733. prechk2:stc                ; carry set for out of range
  1734.     ret
  1735.  
  1736. ; Set checksum length. AL holds their checksum request.
  1737. dochk:    cmp    al,'1'            ; Must be '1', '2', or '3'
  1738.     jb    doc1            ; b = not '1' to '3'
  1739.     cmp    al,'3'
  1740.     jbe    doc2            ; be = ok
  1741. doc1:    mov    al,'1'            ; else use default of '1'
  1742. doc2:    sub    al,'0'            ; remove ascii bias
  1743.     mov    trans.chklen,al        ; other side's request is do-able here
  1744.     ret
  1745.  
  1746. ; Set repeat count quote character.  The one used must be different than
  1747. ; the control and eight-bit quote characters.  Also, both sides must 
  1748. ; use the same character
  1749. dorpt:    mov    trans.rptq,0        ; assume will not repeat prefix
  1750.     call    prechk            ; Is it in the valid range?
  1751.     jnc    dorpt1            ; nc = in range
  1752.     xor    al,al            ; don't use their value 
  1753. dorpt1:    cmp    al,trans.squote        ; same as the control quote char?
  1754.     je    dorpt2            ; e = yes, that's illegal, no repeats
  1755.     cmp    al,trans.rquote        ; this too?
  1756.     je    dorpt2            ; e = no good either
  1757.     cmp    al,trans.ebquot        ; same as eight bit quote char?
  1758.     je    dorpt2            ; e = yes, illegal too, no repeats
  1759.     cmp    al,dtrans.rptq        ; both sides using same char?
  1760.     jne    dorpt2            ; ne = no, that's no good either
  1761.     mov    trans.rptq,al        ; use repeat quote char now
  1762. dorpt2:    ret
  1763.  
  1764.                     ; negotiate window size in al
  1765. dewind:    cmp    al,dtrans.windo        ; their (al) vs our max window size
  1766.     jbe    dewind1            ; be = they want less than we can do
  1767.     mov    al,dtrans.windo        ; limit to our max size
  1768. dewind1:or    al,al
  1769.     jnz    dewind2
  1770.     inc    al            ; use 1 if 0
  1771. dewind2:mov    trans.windo,al        ; store active window size
  1772.     ret
  1773.  
  1774.  
  1775. ; Set the maximum send data packet size; modified for long packets
  1776. PACKLEN    PROC    NEAR
  1777.     push    ax
  1778.     push    cx
  1779.     xor    ah,ah
  1780.     mov    al,trans.spsiz    ; Maximum send packet size for Regular pkts. 
  1781.     cmp    ax,trans.slong        ; negotiated long packet max size
  1782.     jae    packle2            ; ae = use regular packets
  1783.     mov    ax,trans.slong        ; else use long kind
  1784.     sub    ax,3            ; minus extended count & checksum
  1785.     cmp    ax,(95*94-1-2)        ; longer than Long?
  1786.     jle    packle2            ; le = no, Long will do
  1787.     dec    ax            ; minus one more for extra long count
  1788. packle2:sub    ax,2            ; minus Sequence, Type
  1789.     sub    al,trans.chklen        ; and minus Checksum chars
  1790.     sbb    ah,0            ; borrow propagate
  1791.     cmp    trans.ebquot,'N'    ; doing 8-bit Quoting?
  1792.     je    packle0            ; e = no, so we've got our size
  1793.     cmp    trans.ebquot,'Y'
  1794.     je    packle0            ; e = not doing it in this case either
  1795.     dec    ax            ; another 1 for 8th-bit Quoting. 
  1796. packle0:cmp    trans.rptq,0        ; doing repeat character Quoting?
  1797.     je    packle1            ; e = no, so that's all for now
  1798.     dec    ax            ; minus repeat prefix
  1799.     dec    ax            ;  and repeat count
  1800. packle1:dec    ax            ; for last char might being a control code
  1801.     mov    trans.maxdat,ax        ; save max length for data field
  1802.     pop    cx
  1803.     pop    ax
  1804.     ret
  1805. PACKLEN    ENDP
  1806.  
  1807.  ; Print the number in AX on the screen in decimal rather that hex
  1808.  
  1809. NOUT     PROC    NEAR
  1810.     test    flags.remflg,dserver    ; server mode?
  1811.     jnz    nout2            ; nz = yes, writing to their screen
  1812.     cmp    flags.xflg,0        ; receiving to screen?
  1813.     jne    nout1            ; ne = yes
  1814. nout2:    test    flags.remflg,dserial     ; serial display mode?
  1815.     jnz    pnout            ; nz = use "dot and plus" for serial mode
  1816.     test    flags.remflg,dquiet    ; quiet display mode?
  1817.     jnz    nout1            ; nz = yes. Don't write to screen
  1818.     call    decout            ; call standard decimal output routine
  1819. nout1:    ret
  1820.  
  1821. pnout:    or    ax,ax            ; display packet in serial display mode
  1822.     jz    pnoutx            ; z = nothing to display
  1823.     push    ax            ; for serial mode display
  1824.     push    cx
  1825.     push    dx            ; output .........+.........+  etc
  1826.     xor    dx,dx            ; extended numerator
  1827.     mov    cx,10
  1828.     div    cx            ; number/10. (AX=quo, DX=rem)
  1829.     or    dx,dx            ; remainder non-zero?
  1830.     jnz    pnout1            ; nz = yes
  1831.     mov    dl,'+'            ; symbol plus for tens
  1832.     jmp    short pnout2        ; display it
  1833. pnout1:    mov    dl,'.'            ; symbol for between tens
  1834. pnout2:    mov    ah,conout        ; output to console
  1835.     int    dos
  1836.     pop    dx
  1837.     pop    cx
  1838.     pop    ax
  1839. pnoutx:    ret
  1840. NOUT    ENDP
  1841.  
  1842. ; Decode and display Error packet message. 
  1843. ERROR    PROC    NEAR
  1844.     mov    sstate,'A'        ; Set the state to abort
  1845.     push    si
  1846.     mov    si,offset rpacket    ; source address
  1847.     call    dodec            ; decode to decbuf
  1848.     mov    dx,offset decbuf    ; where msg got decoded, asciiz
  1849.     call    ermsg            ; display string
  1850.     pop    si
  1851.     stc                ; set carry for failure state
  1852.     ret
  1853. ERROR    ENDP
  1854.  
  1855. ; General routine for sending an error packet.  Register BX should
  1856. ; point to the text of the message being sent in the packet
  1857.  
  1858. ERRPACK    PROC    NEAR
  1859.     push    cx
  1860.     push    di
  1861.     mov    di,offset encbuf    ; Where to put the message
  1862.     xor    cx,cx
  1863. errpa1:    mov    al,[bx]
  1864.     inc    bx
  1865.     cmp    al,'$'            ; at end of message?
  1866.     je    errpa2            ; e = terminator
  1867.     or    al,al            ; this kind of terminator too?
  1868.     jz    errpa2            ; z = terminator
  1869.     inc    cx            ; count number of chars in msg
  1870.     mov    [di],al            ; copy message
  1871.     inc    di
  1872.     jmp    short errpa1
  1873. errpa2:    push    si
  1874.     mov    si,offset rpacket    ; use response buffer
  1875.     mov    al,pktnum
  1876.     mov    rpacket.seqnum,al
  1877.     call    doenc
  1878.     call    pktsize            ; report packet size
  1879.     mov    rpacket.pktype,'E'    ; send an error packet
  1880.     call    spack
  1881.     mov    rpacket.datlen,0    ; clear response buffer
  1882.     pop    si
  1883.     pop    di
  1884.     pop    cx
  1885.     ret
  1886. ERRPACK    ENDP
  1887.  
  1888. ; Enter with dx pointing to asciiz error message to be sent
  1889. giveup    proc near
  1890.     call    bufclr            ; release all buffers
  1891.     call    ermsg            ; position cursor, display asciiz msg
  1892.     mov    bx,dx
  1893.     call    errpack            ; send error packet
  1894.     xor    ax,ax
  1895.     mov    auxfile,al        ; clear send-as/mail-to buffer
  1896.     mov    mailflg,al        ; clear Mail flag
  1897.     cmp    filopn,al        ; disk files open?
  1898.     je    giveu2            ; e = no so don't do a close
  1899.     mov    ah,close2        ; close file
  1900.     push    bx
  1901.     mov    bx,diskio.handle    ; file handle
  1902.     int    dos
  1903.     pop    bx
  1904.     mov    filopn,0        ; say file is closed now
  1905. giveu2:    mov    sstate,'A'        ; abort state
  1906.     or    errlev,kssend        ; set DOS error level
  1907.     or    fsta.xstatus,kssend    ; set status
  1908.     mov    kstatus,kssend        ; global status
  1909.     stc                ; set carry for failure status
  1910.     ret
  1911. giveup    endp
  1912.  
  1913. code    ends 
  1914.     end
  1915.